#include <head.h>

typedef struct msg
{
     uint32_t ip;
     uint16_t port;
     char buf[1000];//消息的内容
}MSG;


uint32_t stringIPtoNum(char *pIP)
{
    uint32_t nIP = 0;
    // AF_INET是代表IPV4地址的意思，AF_INET6代表IPV6
    inet_pton(AF_INET, pIP, &nIP);
    return nIP;
}

// 把数字IP转为字符串IP
void numIPtoString(uint32_t ip, char *psIP, int size)
{
    inet_ntop(AF_INET, &ip, psIP, size);
}

int main(int argc, char const *argv[])
{
    // 创建一个SOCKET，并且返回一个套接字的文件描述符
    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1)
    {
        perror("");
    }

    int val = 1; // 1代表打开地址重复利用功能，0代表关闭
     // SOL_SOCKET是通用socket设置的意思
     // SO_REUSEADDR是地址重复利用的意思
     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));

    // 地址结构体，需要填写IP，端口，地址族（IPV4/IPV6）
    //  typedef struct sockaddr_in MYADDR;
    struct sockaddr_in addr;
    addr.sin_addr.s_addr = stringIPtoNum("192.168.70.37"); // 指定IP
    addr.sin_port = htons(9001);                           // 指定端口
    addr.sin_family = AF_INET;                             // 指定地址协议族

    // 第二个参数因为历史原因，系统设定的是struct sockaddr类型，而现在常用的类型是struct sockaddr_in
    // 所以这里要做一个强制转换
    if (-1 == bind(fd, (struct sockaddr *)&addr, sizeof(addr)))
    {
        perror("");
    }
    // 启动监听功能，允许5个客户端排队等待
    if (-1 == listen(fd, 5))
    {
        perror("");
    }
    fd_set readSet;
    FD_ZERO(&readSet);
    FD_SET(fd, &readSet);
    fd_set oldSet = readSet;
    int maxFD = fd;
    int oldMAX = maxFD;
    while (1)
    {
        int ret = select(maxFD + 1, &readSet, NULL, NULL, NULL);
        if (ret == -1)
        {
            perror("");
        }
        else
        {
            for (int i = 3; i <= maxFD; i++)
            {
                
                if (FD_ISSET(i, &readSet))
                {
                    printf("套接字%d有可读事件\n", i);
                    if (i == fd)
                    {
                        struct sockaddr_in clientAddr;
                        socklen_t len = sizeof(clientAddr);
                        int newSocketFD = accept(fd, (struct sockaddr *)&clientAddr, &len);
                        
                        if (newSocketFD == -1)
                        {
                            perror("newSocketFD");
                        }
                        printf("新连接：%s:%d\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
                        oldMAX = (oldMAX > newSocketFD ? oldMAX : newSocketFD);
                        FD_SET(newSocketFD, &oldSet);
                    }
                    else
                    {
                        printf("套接字%d可读\n", i);
                        MSG m1;
                        int ret = read(i, &m1, sizeof(m1));
                        if (ret <= 0)
                        {
                            close(i);
                            FD_CLR(i, &readSet);
                            printf("客户端断开连接\n");
                        }
                        else
                        {
                            printf("接收到消息：%s\n", m1.buf);
                        }
                    }
                }
            }
            maxFD = oldMAX;
            readSet = oldSet;
        }
    }
    close(fd);
    return 0;
}